<!doctype html>
<html>
    <head>
        <meta charset='utf-8'>
        <meta name='timeout' content='long'>
<script src='/resources/testharness.js'></script>
        <script src='/resources/testharnessreport.js'></script>
        <script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src='../mediacapture-streams/permission-helper.js'></script>
    </head>
    <body>
        <video id='video1' autoplay></video>
        <script src ='routines.js'></script>
        <script>
async function waitForMessage(worker, data)
{
    while (true) {
        const received = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
        if (data === received)
            return;
    }
}

async function gatherMetadata(test, kind)
{
    worker = new Worker('script-metadata-transform-worker.js');
    const data = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
    assert_equals(data, 'registered');

    // Both audio and vido are needed at one time or another
    // so asking for both permissions
    await setMediaPermission();
    const localStream = await navigator.mediaDevices.getUserMedia({[kind]: true});

    let sender, receiver;
    const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
    const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});

    await new Promise((resolve, reject) => {
        createConnections(test, (firstConnection) => {
            pc1 = firstConnection;
            sender = firstConnection.addTrack(localStream.getTracks()[0], localStream);
            sender.transform = senderTransform;
        }, (secondConnection) => {
            pc2 = secondConnection;
            secondConnection.ontrack = (trackEvent) => {
                receiver = trackEvent.receiver;
                receiver.transform = receiverTransform;
                resolve(trackEvent.streams[0]);
            };
        });
        test.step_timeout(() => reject('Test timed out'), 5000);
    });

    let senderBeforeWrite, senderAfterWrite, receiverBeforeWrite, receiverAfterWrite;
    while (true) {
        const {data} = await new Promise(r => worker.onmessage = r);
        if (data.name == 'sender') {
            senderBeforeWrite = data;
        } else if (data.name == 'receiver') {
            receiverBeforeWrite = data;
        } else if (data.name == 'sender after write') {
            senderAfterWrite = data;
        } else if (data.name == 'receiver after write') {
            receiverAfterWrite = data;
        }
        if (senderBeforeWrite &&
            senderAfterWrite &&
            receiverBeforeWrite &&
            receiverAfterWrite) {
            return {
              senderBeforeWrite,
              senderAfterWrite,
              receiverBeforeWrite,
              receiverAfterWrite
            };
        }
    }
}

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'audio');

    assert_equals(typeof data.senderBeforeWrite.timestamp, 'number');
    assert_not_equals(data.senderBeforeWrite.timestamp, 0);
    assert_equals(data.senderBeforeWrite.timestamp,
      data.senderAfterWrite.timestamp,
      'timestamp matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.timestamp,
      data.receiverBeforeWrite.timestamp,
      'timestamp matches (for sender and receiver)');
    assert_equals(data.receiverBeforeWrite.timestamp,
      data.receiverAfterWrite.timestamp,
      'timestamp matches (for receiver before and after write)');
}, 'audio metadata: timestamp');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'audio');

    assert_equals(typeof data.senderBeforeWrite.metadata.synchronizationSource, 'number');
    assert_not_equals(data.senderBeforeWrite.metadata.synchronizationSource, 0);
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.senderAfterWrite.metadata.synchronizationSource,
      'ssrc matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.receiverBeforeWrite.metadata.synchronizationSource,
      'ssrc matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.receiverAfterWrite.metadata.synchronizationSource,
      'ssrc matches (for receiver before and after write)');
}, 'audio metadata: synchronizationSource');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'audio');

    assert_equals(typeof data.senderBeforeWrite.metadata.payloadType, 'number');
    assert_equals(data.senderBeforeWrite.metadata.payloadType,
      data.senderAfterWrite.metadata.payloadType,
      'payload type matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.payloadType,
      data.receiverBeforeWrite.metadata.payloadType,
      'payload type matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.payloadType,
      data.receiverAfterWrite.metadata.payloadType,
      'payload type matches (for receiver before and after write)');
}, 'audio metadata: payloadType');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'audio');

    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.senderAfterWrite.metadata.contributingSources,
      'csrcs are arrays, and match (for sender before and after write)');
    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.receiverBeforeWrite.metadata.contributingSources,
      'csrcs are arrays, and match');
    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.receiverAfterWrite.metadata.contributingSources,
      'csrcs are arrays, and match (for receiver before and after write)');
}, 'audio metadata: contributingSources');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'audio');

    assert_equals(typeof data.receiverBeforeWrite.metadata.sequenceNumber,
      'number');
    assert_equals(data.receiverBeforeWrite.metadata.sequenceNumber,
      data.receiverAfterWrite.metadata.sequenceNumber,
      'sequenceNumber matches (for receiver before and after write)');
    // spec says sequenceNumber exists only for incoming audio frames
    assert_equals(data.senderBeforeWrite.metadata.sequenceNumber, undefined);
    assert_equals(data.senderAfterWrite.metadata.sequenceNumber, undefined);
}, 'audio metadata: sequenceNumber');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.timestamp, 'number');
    assert_equals(data.senderBeforeWrite.timestamp,
      data.senderAfterWrite.timestamp,
      'timestamp matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.timestamp,
      data.receiverBeforeWrite.timestamp,
      'timestamp matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.timestamp,
      data.receiverAfterWrite.timestamp,
      'timestamp matches (for receiver before and after write)');
}, 'video metadata: timestamp');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.metadata.synchronizationSource,
      'number');
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.senderAfterWrite.metadata.synchronizationSource,
      'ssrc matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.receiverBeforeWrite.metadata.synchronizationSource,
      'ssrc matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.synchronizationSource,
      data.receiverAfterWrite.metadata.synchronizationSource,
      'ssrc matches (for receiver before and after write)');
}, 'video metadata: ssrc');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.senderAfterWrite.metadata.contributingSources,
      'csrcs are arrays, and match (for sender before and after write)');
    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.receiverBeforeWrite.metadata.contributingSources,
      'csrcs are arrays, and match');
    assert_array_equals(data.senderBeforeWrite.metadata.contributingSources,
      data.receiverAfterWrite.metadata.contributingSources,
      'csrcs are arrays, and match (for receiver before and after write)');
}, 'video metadata: csrcs');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.metadata.height, 'number');
    assert_equals(data.senderBeforeWrite.metadata.height,
      data.senderAfterWrite.metadata.height,
      'height matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.height,
      data.receiverBeforeWrite.metadata.height,
      'height matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.height,
      data.receiverAfterWrite.metadata.height,
      'height matches (for receiver before and after write)');
    assert_equals(typeof data.senderBeforeWrite.metadata.width, 'number');
    assert_equals(data.senderBeforeWrite.metadata.width,
      data.senderAfterWrite.metadata.width,
      'width matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.width,
      data.receiverBeforeWrite.metadata.width,
      'width matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.width,
      data.receiverAfterWrite.metadata.width,
      'width matches (for receiver before and after write)');
}, 'video metadata: width and height');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.metadata.spatialIndex,
      'number');
    assert_equals(data.senderBeforeWrite.metadata.spatialIndex,
      data.senderAfterWrite.metadata.spatialIndex,
      'spatialIndex matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.spatialIndex,
      data.receiverBeforeWrite.metadata.spatialIndex,
      'spatialIndex matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.spatialIndex,
      data.receiverAfterWrite.metadata.spatialIndex,
      'spatialIndex matches (for receiver before and after write)');
    assert_equals(typeof data.senderBeforeWrite.metadata.temporalIndex,
      'number');
    assert_equals(data.senderBeforeWrite.metadata.temporalIndex,
      data.senderAfterWrite.metadata.temporalIndex,
      'temporalIndex matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.temporalIndex,
      data.receiverBeforeWrite.metadata.temporalIndex,
      'temporalIndex matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.temporalIndex,
      data.receiverAfterWrite.metadata.temporalIndex,
      'temporalIndex matches (for receiver before and after write)');
}, 'video metadata: spatial and temporal index');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_array_equals(data.senderBeforeWrite.metadata.dependencies,
      data.senderAfterWrite.metadata.dependencies,
      'dependencies are arrays, and match (for sender before and after write)');
    assert_array_equals(data.senderBeforeWrite.metadata.dependencies,
      data.receiverBeforeWrite.metadata.dependencies,
      'dependencies are arrays, and match (for sender and receiver)');
    assert_array_equals(data.senderBeforeWrite.metadata.dependencies,
      data.receiverAfterWrite.metadata.dependencies,
      'dependencies are arrays, and match (for receiver before and after write)');
}, 'video metadata: dependencies');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.metadata.frameId, 'number');
    assert_equals(data.senderBeforeWrite.metadata.frameId,
      data.senderAfterWrite.metadata.frameId,
      'frameId matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.metadata.frameId,
      data.receiverBeforeWrite.metadata.frameId,
      'frameId matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.metadata.frameId,
      data.receiverAfterWrite.metadata.frameId,
      'frameId matches (for receiver before and after write)');
}, 'video metadata: frameId');

promise_test(async (test) => {
    const data = await gatherMetadata(test, 'video');

    assert_equals(typeof data.senderBeforeWrite.type, 'string');
    assert_true(data.senderBeforeWrite.type == 'key' || data.senderBeforeWrite.type == 'delta');
    assert_equals(data.senderBeforeWrite.type,
      data.senderAfterWrite.type,
      'type matches (for sender before and after write)');
    assert_equals(data.senderBeforeWrite.type,
      data.receiverBeforeWrite.type,
      'type matches (for sender and receiver)');
    assert_equals(data.senderBeforeWrite.type,
      data.receiverAfterWrite.type,
      'type matches (for receiver before and after write)');
}, 'video metadata: type');

        </script>
    </body>
</html>
